#include "tcpserversingleton.h"

// 单例对象, 提供给外界使用的唯一一个对象的指针
tcpServerSingleton *tcpServerSingleton::tcpServer = nullptr;

// 屏蔽构造函数后, 必须提供至少一个static函数
// 用来让用户生成且获取(如果之前以及生成过, 就直接获取)
tcpServerSingleton *tcpServerSingleton::create_tcpServer()
{
    if(tcpServer == nullptr)
        tcpServer = new tcpServerSingleton;
    return tcpServer;
}
tcpServerSingleton *tcpServerSingleton::create_tcpServer(const QString &ip, int port)
{
    if(tcpServer == nullptr)
        tcpServer = new tcpServerSingleton(ip, port);
    return tcpServer;
}

// 屏蔽析构函数后, 必须提供一个销毁功能的函数给用户使用
void tcpServerSingleton::destroy_tcpServer()
{
    if(tcpServer != nullptr)
        delete tcpServer;
    tcpServer = nullptr;
}

// 其他普通函数
const QTcpServer *tcpServerSingleton::get_server() const
{
    return this->server;
}
const QTcpSocket *tcpServerSingleton::get_socket() const
{
    return this->server_socket;
}
const QString &tcpServerSingleton::get_listen_ip() const
{
    return this->listen_ip;
}
void tcpServerSingleton::set_listen_ip(const QString &ip)
{
    this->listen_ip = ip;
}
int tcpServerSingleton::get_listen_port() const
{
    return this->listen_port;
}
void tcpServerSingleton::set_listen_port(int port)
{
    this->listen_port = port;
}
const QString &tcpServerSingleton::get_client_ip()
{
    client_ip = server_socket->peerAddress().toString();
    return client_ip;
}
const QString &tcpServerSingleton::get_client_port()
{
    client_port = QString::number(server_socket->peerPort());
    return client_port;
}
void tcpServerSingleton::show() const
{
    qDebug() << "ip = " << this->listen_ip << ", port = " << this->listen_port;
}

// 构造函数, 虽然对外界屏蔽, 但是内部create_tcpServer还是会调用, 因此需要写具体的构造内容
tcpServerSingleton::tcpServerSingleton(QWidget *parent)
    : QObject(parent), listen_ip("0.0.0.0"), listen_port(10000)
{
    // 1.初始化网络模块
    server = new QTcpServer(this);
    server_socket = nullptr;

    // 2.开始监听
    server->listen(QHostAddress(listen_ip), listen_port);

    // 3.信号处理
    this->connect(server, &QTcpServer::newConnection, this, &tcpServerSingleton::slot_newConnection);

}
tcpServerSingleton::tcpServerSingleton(const QString &ip, int port, QWidget *parent)
    : QObject(parent), listen_ip(ip), listen_port(port)
{
    // 1.初始化网络模块
    server = new QTcpServer(this);
    server_socket = nullptr;

    // 2.开始监听
    server->listen(QHostAddress(listen_ip), listen_port);

    // 3.信号处理
    this->connect(server, &QTcpServer::newConnection, this, &tcpServerSingleton::slot_newConnection);
}

// 析构, 虽然没有内容, 但是需要用private屏蔽
tcpServerSingleton::~tcpServerSingleton()
{}

// 槽函数
void tcpServerSingleton::slot_newConnection()
{
    // 有连接
    bool ret = server_socket = server->nextPendingConnection();
    if(ret)
    {
        QString client_ip = server_socket->peerAddress().toString();
        QString client_port = QString::number(server_socket->peerPort());
        QString client_message = "Connect from client ip: " + client_ip + ", port: " + client_port;
        emit sig_recv(client_message);
        server_socket->write(client_message.toUtf8());
    }

    this->connect(server_socket, &QTcpSocket::readyRead, this, &tcpServerSingleton::slot_socket_readyRead);
    this->connect(server_socket, &QTcpSocket::disconnected, this, &tcpServerSingleton::slot_socket_disconnected);
}
void tcpServerSingleton::slot_socket_readyRead()
{
    // 接收
    // 使用.trimmed()去除​​两端空白符​​（包括空格、制表符、换行符）
    QByteArray recv_msg_arr = server_socket->readAll().trimmed();
    QString recv = QString::fromUtf8(recv_msg_arr);
    emit sig_recv(recv);
    // QString send = recv + "000";
    // server_socket->write(send.toUtf8());
}
void tcpServerSingleton::slot_socket_disconnected()
{
    // server_socket已经没有用处了，提醒QApplication稍后删除
    emit sig_recv(QString("000"));
    server_socket->deleteLater();
    server_socket = nullptr;
}
void tcpServerSingleton::slot_send_data(const QString &send)
{
//    QString send_data = "status: " + send;
    server_socket->write(send.toUtf8());
}
